/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.filesystems; import java.beans.*; import java.io.*; import java.util.Enumeration; import java.util.StringTokenizer; import javax.swing.SwingUtilities; import org.openide.util.actions.SystemAction; import org.openide.util.Queue; import org.openide.util.enum.SequenceEnumeration; import org.openide.util.enum.SingletonEnumeration; /** Implementation of <code>FileSystem</code> that simplifies the most * common tasks. Caches information about the filesystem in * memory and periodically refreshes its content. * Many other operations are performed in a safer manner so as to reuse * known experience; should be substantially simpler to subclass. * * @author Jaroslav Tulach */ public abstract class AbstractFileSystem extends FileSystem { /** generated Serialized Version UID */ static final long serialVersionUID = -3345098214331282438L; /** system actions for this FS if it has refreshTime != 0 */ private static final SystemAction[] SYSTEM_ACTIONS = new SystemAction[] { new RefreshAction () }; /** system actions for this FS */ private static final SystemAction[] NO_SYSTEM_ACTIONS = new SystemAction[] { }; /** root object for the file system */ private transient AbstractFileObject root; /** refresher */ private transient RefreshRequest refresher; /** Provider of hierarchy of files. */ protected List list; /** Methods for modification of files. */ protected Change change; /** Methods for moving of files. This field can be left null if the filesystem * does not require special handling handling of FileObject.move and is satified * with the default implementation. */ protected Transfer transfer; /** Methods for obtaining information about files. */ protected Info info; /** Handling of attributes for files. */ protected Attr attr; /* Provides a name for the system that can be presented to the user. * @return user presentable name of the file system */ public abstract String getDisplayName (); /* Getter for root folder in the filesystem. * * @return root folder of whole filesystem */ public FileObject getRoot () { return getAbstractRoot (); } /* Finds file when its name is provided. * * @param aPackage package name where each package is separated by a dot * @param name name of the file (without dots) or <CODE>null</CODE> if * one want to obtain name of package and not file in it * @param ext extension of the file or <CODE>null</CODE> if one needs * package and not file name * * @warning when one of name or ext is <CODE>null</CODE> then name and * ext should be ignored and scan should look only for a package * * @return FileObject that represents file with given name or * <CODE>null</CODE> if the file does not exist */ public FileObject find (String aPackage, String name, String ext) { // create enumeration of name to look for StringTokenizer st = new StringTokenizer (aPackage, "."); // NOI18N Enumeration en; if (name == null || ext == null) { en = st; } else { en = new SequenceEnumeration ( st, new SingletonEnumeration (name + '.' + ext) ); } // tries to find it (can return null) return getAbstractRoot ().find (en); } /* Finds file when its resource name is given. * The name has the usual format for the {@link ClassLoader#getResource(String)} * method. So it may consist of "package1/package2/filename.ext". * If there is no package, it may consist only of "filename.ext". * * @param name resource name * * @return FileObject that represents file with given name or * <CODE>null</CODE> if the file does not exist */ public FileObject findResource (String name) { if (name.length () == 0) { return getAbstractRoot (); } else { StringTokenizer tok = new StringTokenizer (name, "/"); // NOI18N return getAbstractRoot ().find (tok); } } /* Action for this filesystem. * * @return refresh action */ public SystemAction[] getActions () { return refresher == null ? NO_SYSTEM_ACTIONS : SYSTEM_ACTIONS; } /** Set the number of milliseconds between automatic * refreshes of the directory structure. * * @param ms number of milliseconds between two refreshes; if <code><= 0</code> then refreshing is disabled */ protected synchronized final void setRefreshTime (int ms) { if (refresher != null) { refresher.stop (); } if (ms <= 0 || System.getProperty ("netbeans.debug.heap") != null) { refresher = null; } else { refresher = new RefreshRequest (this, ms); } } /** Get the number of milliseconds between automatic * refreshes of the directory structure. * By default, automatic refreshing is disabled. * @return the number of milliseconds, or <code>0</code> if refreshing is disabled */ protected final int getRefreshTime () { RefreshRequest r = refresher; return r == null ? 0 : r.getRefreshTime (); } /** Instruct the filesystem * that the root should change. * A fresh root is created. Subclasses that support root changes should use this. * * @return the new root */ protected final synchronized AbstractFileObject refreshRoot () { root = createFileObject (null, ""); // NOI18N return root; } /** Allows subclasses to fire that a change occured in a * file or folder. The change can be "expected" when it is * a result of an user action and the user knows that such * change should occur. * * @param name resource name of the file where the change occured * @param expected true if the user initiated change and expects it */ protected final void refreshResource (String name, boolean expected) { AbstractFileObject fo = (AbstractFileObject)findResourceIfExists (name); if (fo != null) { // refresh and behave like the changes is expected fo.refresh (null, null, true, true); } } /* Finds file when its resource name is given. * The name has the usual format for the {@link ClassLoader#getResource(String)} * method. So it may consist of "package1/package2/filename.ext". * If there is no package, it may consist only of "filename.ext". * * @param name resource name * * @return FileObject that represents file with given name or * <CODE>null</CODE> if the file does not exist */ private FileObject findResourceIfExists (String name) { if (name.length () == 0) { return getAbstractRoot (); } else { StringTokenizer tok = new StringTokenizer (name, "/"); // NOI18N return getAbstractRoot ().findIfExists (tok); } } /** Hooking method to allow MultiFileSystem to be informed when a new * file object is created. This is the only method that creates AbstractFileObjects. * * @param parent parent object * @param name of the object */ AbstractFileObject createFileObject (AbstractFileObject parent, String name) { return new AbstractFileObject (this, parent, name); } /** Creates root object for the fs. */ final AbstractFileObject getAbstractRoot () { if (root == null) { synchronized (this) { if (root == null) { return refreshRoot (); } } } return root; } /** Writes the common fields and the state of refresher. */ private void writeObject (ObjectOutputStream oos) throws IOException { oos.defaultWriteObject (); oos.writeInt (getRefreshTime ()); } /** Reads common fields and state of refresher. */ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { ois.defaultReadObject (); setRefreshTime (ois.readInt ()); } /** Provides access to the hierarchy of resources. */ public interface List extends java.io.Serializable { static final long serialVersionUID =-6242105832891012528L; /** Get a list of children files for a given folder. * * @param f the folder, by name; e.g. <code>top/next/afterthat</code> * @return a list of children of the folder, as <code>file.ext</code> (no path) * the array can contain <code>null</code> values that will be ignored */ public String[] children (String f); } /** Controls modification of files. */ public interface Change extends java.io.Serializable { static final long serialVersionUID =-5841597109944924596L; /** Create new folder. * @param name full name of new folder, e.g. <code>topfolder/newfolder</code> * @throws IOException if the operation fails */ public void createFolder (String name) throws java.io.IOException; /** Create new data file. * * @param name full name of the file, e.g. <code>path/from/root/filename.ext</code> * * @exception IOException if the file cannot be created (e.g. already exists) */ public void createData (String name) throws IOException; /** Rename a file. * * @param oldName old name of the file; fully qualified * @param newName new name of the file; fully qualified * @throws IOException if it could not be renamed */ public void rename(String oldName, String newName) throws IOException; /** Delete a file. * * @param name name of file; fully qualified * @exception IOException if the file could not be deleted */ public void delete (String name) throws IOException; } /** Controls on moving of files. This is additional interface to * allow file system that require special handling of move to implement * it in different way then is the default one. */ public interface Transfer extends java.io.Serializable { static final long serialVersionUID =-8945397853892302838L; /** Move a file. * * @param name of the file on current file system * @param target move implementation * @param targetName of target file * @exception IOException if the move fails * @return false if the method is not able to handle the request and * default implementation should be used instead */ public boolean move (String name, Transfer target, String targetName) throws IOException; /** Copy a file. * * @param name of the file on current file system * @param target target transfer implementation * @param targetName name of target file * @exception IOException if the copy fails * @return false if the method is not able to handle the request and * default implementation should be used instead */ public boolean copy (String name, Transfer target, String targetName) throws IOException; } /** Information about files. */ public interface Info extends java.io.Serializable { static final long serialVersionUID =-2438286177948307985L; /** * Get last modification time. * @param name the file to test * @return the date of last modification */ public java.util.Date lastModified(String name); /** Test if the file is a folder or contains data. * @param name name of the file * @return <code>true</code> if the file is folder, <code>false</code> if it is data */ public boolean folder (String name); /** Test whether this file can be written to or not. * @param name the file to test * @return <CODE>true</CODE> if the file is read-only */ public boolean readOnly (String name); /** Get the MIME type of the file. * * @param name the file to test * @return the MIME type textual representation, e.g. <code>"text/plain"</code> */ public String mimeType (String name); /** Get the size of the file. * * @param name the file to test * @return the size of the file in bytes, or zero if the file does not contain data (does not * exist or is a folder). */ public long size (String name); /** Get input stream. * * @param name the file to test * @return an input stream to read the contents of this file * @exception FileNotFoundException if the file does not exist or is invalid */ public InputStream inputStream (String name) throws java.io.FileNotFoundException; /** Get output stream. * * @param name the file to test * @return output stream to overwrite the contents of this file * @exception IOException if an error occurs (the file is invalid, etc.) */ public OutputStream outputStream (String name) throws java.io.IOException; /** Lock the file. * May do nothing if the underlying storage does not support locking. * This does not affect locking using {@link FileLock} within the IDE, however. * @param name name of the file * @throws FileAlreadyLockedException if the file is already locked */ public void lock (String name) throws IOException; /** Unlock the file. * @param name name of the file */ public void unlock (String name); /** Mark the file as being unimportant. * If not called, the file is assumed to be important. * * @param name the file to mark */ public void markUnimportant (String name); } /** Handle attributes of files. */ public interface Attr extends java.io.Serializable { static final long serialVersionUID =5978845941846736946L; /** Get the file attribute with the specified name. * @param name the file * @param attrName name of the attribute * @return appropriate (serializable) value or <CODE>null</CODE> if the attribute is unset (or could not be properly restored for some reason) */ public Object readAttribute(String name, String attrName); /** Set the file attribute with the specified name. * @param name the file * @param attrName name of the attribute * @param value new value or <code>null</code> to clear the attribute. Must be serializable, although particular file systems may or may not use serialization to store attribute values. * @exception IOException if the attribute cannot be set. If serialization is used to store it, this may in fact be a subclass such as {@link NotSerializableException}. */ public void writeAttribute(String name, String attrName, Object value) throws IOException; /** Get all file attribute names for the file. * @param name the file * @return enumeration of keys (as strings) */ public Enumeration attributes(String name); /** Called when a file is renamed, to appropriately update its attributes. * @param oldName old name of the file * @param newName new name of the file */ public void renameAttributes (String oldName, String newName); /** Called when a file is deleted, to also delete its attributes. * * @param name name of the file */ public void deleteAttributes (String name); } } /* * Log * 16 src-jtulach1.15 1/12/00 Ian Formanek NOI18N * 15 src-jtulach1.14 1/5/00 Jaroslav Tulach AbstractFileSystem.refreshResource * modifies lastModified time * 14 src-jtulach1.13 11/25/99 Jaroslav Tulach List.children () can * return array that contains nulls * 13 src-jtulach1.12 11/24/99 Jaroslav Tulach FileEvent can be expected * + fired by AbstractFileSystem * 12 src-jtulach1.11 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 11 src-jtulach1.10 10/1/99 Jaroslav Tulach FileObject.move & * FileObject.copy * 10 src-jtulach1.9 9/16/99 Petr Hrebejk -D netbeans.debug.heap * for no filesystem refresh added * 9 src-jtulach1.8 8/9/99 Ian Formanek Generated Serial Version * UID * 8 src-jtulach1.7 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 7 src-jtulach1.6 6/3/99 Jaroslav Tulach Refresh of only opened * files. * 6 src-jtulach1.5 5/24/99 Jaroslav Tulach * 5 src-jtulach1.4 3/26/99 Jesse Glick [JavaDoc] * 4 src-jtulach1.3 3/26/99 Jaroslav Tulach Refresh & Bundles * 3 src-jtulach1.2 3/26/99 Jaroslav Tulach * 2 src-jtulach1.1 3/24/99 Jesse Glick [JavaDoc] partial. * 1 src-jtulach1.0 3/24/99 Jaroslav Tulach * $ */